package com.a1anwang.okble.demo.ability;

import com.a1anwang.okble.client.core.OKBLEDeviceListener;
import com.a1anwang.okble.client.core.OKBLEOperation;
import com.a1anwang.okble.common.OKBLECharacteristicModel;
import com.a1anwang.okble.common.OKBLEDataUtils;
import com.a1anwang.okble.demo.APP;
import com.a1anwang.okble.demo.ResourceTable;
import com.a1anwang.okble.demo.base.BaseAbility;
import com.a1anwang.okble.demo.views.WriteInputPopupWindow;
import ohos.agp.components.Button;
import ohos.agp.components.Component;
import ohos.agp.components.Image;
import ohos.agp.components.Text;
import ohos.agp.utils.Color;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.eventhandler.InnerEvent;

import java.sql.Timestamp;
import java.util.Arrays;

/**
 * Created by a1anwang.com on 2018/5/23.
 */
public class CharacteristicAbility extends BaseAbility implements OKBLEDeviceListener {
    private static final int READ_FAILED = 1;
    private static final int READ_SUCCESS = 0;
    private static final int WRITE_SUCCESS = 2;
    private static final int WRITE_FAILED = 3;
    private static final int INDICATE_SUCCESS = 4;
    private static final int INDICATE_FAILED = 5;
    private static final int EXECUTE_SUCCESS = 6;
    private static final int RECEIVED_VALUE = 7;
    OKBLECharacteristicModel characteristicModel;
    WriteInputPopupWindow inputPopupWindow = null;
    Text tvTitle;
    Button btnRead;
    Button btnWrite;
    Button btnNotify;
    Button btnIndicate;
    Button btnClear;
    Image btnLeft;
    Text tvLog;
    String uuidTemp = null;
    EventHandler eventHandler = new EventHandler(EventRunner.getMainEventRunner());
    // create()的参数是true时，则为托管模式;
    EventRunner runner = EventRunner.create(true);
    MyEventHandler handler = new MyEventHandler(runner);
    private APP application = APP.getApp();
    private final OKBLEOperation.OperationType[] operationType = new OKBLEOperation.OperationType[1];

    @Override
    protected void onStop() {
        super.onStop();
        if (application.okbleDevice != null) {
            application.okbleDevice.removeDeviceListener(this);
        }
    }

    @Override
    public boolean isFullScreen() {
        return false;
    }

    @Override
    public void setContentLayout() {
        setUIContent(ResourceTable.Layout_ability_characteristic);
    }

    @Override
    public void beforeInitView() {
        characteristicModel = APP.getApp().getCharacteristicModel();
    }

    @Override
    public void initView() {
        setHeadVisibility(Component.VISIBLE);
        btnLeft = (Image) findComponentById(ResourceTable.Id_btn_left);
        tvTitle = (Text) findComponentById(ResourceTable.Id_tv_title);
        tvLog = (Text) findComponentById(ResourceTable.Id_tv_log);
        btnClear = (Button) findComponentById(ResourceTable.Id_btn_clear);
        btnClear.setClickedListener(this);
        btnLeft.setClickedListener(this);
        btnRead = (Button) findComponentById(ResourceTable.Id_btn_read);
        btnWrite = (Button) findComponentById(ResourceTable.Id_btn_write);
        btnNotify = (Button) findComponentById(ResourceTable.Id_btn_notify);
        btnIndicate = (Button) findComponentById(ResourceTable.Id_btn_indicate);
        btnRead.setClickedListener(this);
        btnWrite.setClickedListener(this);
        btnNotify.setClickedListener(this);
        btnIndicate.setClickedListener(this);
        if (characteristicModel != null) {
            tvTitle.setText(characteristicModel.getUuid());
            if (characteristicModel.isCanRead()) {
                btnRead.setVisibility(Component.VISIBLE);
            } else {
                btnRead.setVisibility(Component.HIDE);
            }
            if (characteristicModel.isCanWrite() || characteristicModel.isCanWriteNoResponse()) {
                btnWrite.setVisibility(Component.VISIBLE);
            } else {
                btnWrite.setVisibility(Component.HIDE);
            }
            if (characteristicModel.isCanNotify()) {
                btnNotify.setVisibility(Component.VISIBLE);
                if (application.okbleDevice.isNotifyEnabled(characteristicModel.getUuid())) {
                    btnNotify.setText("Notification enabled");
                    btnNotify.setTextColor(Color.GRAY);
                    btnNotify.setEnabled(false);
                } else {
                    btnNotify.setText("Notification disabled");
                }
            } else {
                btnNotify.setVisibility(Component.HIDE);
            }
            if (characteristicModel.isCanIndicate()) {
                btnIndicate.setVisibility(Component.VISIBLE);
                if (application.okbleDevice.isIndicateEnabled(characteristicModel.getUuid())) {
                    btnIndicate.setText("Indication enabled");
                    btnIndicate.setTextColor(Color.GRAY);
                    btnIndicate.setEnabled(false);
                } else {
                    btnIndicate.setText("Indication disabled");
                }
            } else {
                btnIndicate.setVisibility(Component.HIDE);
            }
            application.okbleDevice.addDeviceListener(this);
        }
    }

    @Override
    public void afterInitView() {
    }

    class MyEventHandler extends EventHandler {
        private MyEventHandler(EventRunner runner) {
            super(runner);
        }

        @Override
        public void processEvent(InnerEvent event) {
            super.processEvent(event);
            if (event == null) {
                return;
            }
            int eventId = event.eventId;
            switch (eventId) {
                case READ_SUCCESS:
                    byte[] value = (byte[]) event.object;
                    addLog("onReadValue:" + OKBLEDataUtils.BytesToHexString(value) + " (" + new String(value) + ")");
                    break;
                case READ_FAILED:
                    String errMsg = (String) event.object;
                    addLog("read onFail:" + errMsg);
                    break;
                case WRITE_SUCCESS:
                    byte[] b = (byte[]) event.object;
                    addLog(" onWriteValue:" + Arrays.toString(b));
                    break;
                case WRITE_FAILED:
                    String err = (String) event.object;
                    addLog("write onFail:" + err);
                    break;
                case INDICATE_SUCCESS:
                    addLog("onNotifyOrIndicateComplete");
                    if (operationType[0] == OKBLEOperation.OperationType.OperationType_Enable_Indicate) {
                        btnIndicate.setText("Indication enabled");
                        btnNotify.setTextColor(Color.GRAY);
                        btnIndicate.setEnabled(false);
                    } else if (operationType[0] == OKBLEOperation.OperationType.OperationType_Enable_Notify) {
                        btnNotify.setText("Notification enabled");
                        btnNotify.setTextColor(Color.GRAY);
                        btnNotify.setEnabled(false);
                    }
                    break;
                case INDICATE_FAILED:
                    String msg = (String) event.object;
                    addLog("NotifyOrIndicate onFail:" + msg);
                    break;
                case EXECUTE_SUCCESS:
                    String v = (String) event.object;
                    addLog("write value execute success value length:" + OKBLEDataUtils.hexStringToBytes(v).length + " value:" + v);
                    break;
                case RECEIVED_VALUE:
                    byte[] t = (byte[]) event.object;
                    addLog("onReceivedValue UUID:" + uuidTemp.toString() + " value:" + OKBLEDataUtils.BytesToHexString(t).toString());
                    break;
                default:
                    break;
            }
        }
    }

    @Override
    public void onClickEvent(Component v) {
        switch (v.getId()) {
            case ResourceTable.Id_btn_read:
                application.okbleDevice.addReadOperation(characteristicModel.getUuid(), new OKBLEOperation.ReadOperationListener() {
                    @Override
                    public void onReadValue(final byte[] value) {
                        addLog("onReadValue:" + OKBLEDataUtils.BytesToHexString(value) + " (" + new String(value) + ")");
                    }

                    @Override
                    public void onFail(int code, final String errMsg) {
                        addLog("read onFail:" + errMsg);
                    }

                    @Override
                    public void onExecuteSuccess(OKBLEOperation.OperationType type) {
                    }
                });
                break;
            case ResourceTable.Id_btn_write:
                if (inputPopupWindow == null) {
                    inputPopupWindow = new WriteInputPopupWindow(this);
                    inputPopupWindow.setInputListener(new WriteInputPopupWindow.InputListener() {
                        @Override
                        public void onInputComplete(final String value) {
                            if (value.length() > 0) {
                                application.okbleDevice.addWriteOperation(characteristicModel.getUuid(), value, new OKBLEOperation.WriteOperationListener() {
                                    @Override
                                    public void onWriteValue(final byte[] byteValue) {
                                        addLog(" onWriteValue:" + Arrays.toString(byteValue));
                                    }

                                    @Override
                                    public void onFail(int code, final String errMsg) {
                                        addLog("write onFail:" + errMsg);
                                    }

                                    @Override
                                    public void onExecuteSuccess(OKBLEOperation.OperationType type) {
                                        addLog("write value execute success value length:" + OKBLEDataUtils.hexStringToBytes(value).length + " value:" + value);
                                    }
                                });
                            }
                        }
                    });
                }
                inputPopupWindow.showAt();
                break;
            case ResourceTable.Id_btn_notify:
            case ResourceTable.Id_btn_indicate:
                application.okbleDevice.addNotifyOrIndicateOperation(characteristicModel.getUuid(), true, new OKBLEOperation.NotifyOrIndicateOperationListener() {
                    @Override
                    public void onNotifyOrIndicateComplete() {
                        eventHandler.postTask(new Runnable() {
                            @Override
                            public void run() {
                                addLog("onNotifyOrIndicateComplete");
                                if (operationType[0] == OKBLEOperation.OperationType.OperationType_Enable_Indicate) {
                                    btnIndicate.setText("Indication enabled");
                                    btnIndicate.setTextColor(Color.GRAY);
                                    btnIndicate.setEnabled(false);
                                } else if (operationType[0] == OKBLEOperation.OperationType.OperationType_Enable_Notify) {
                                    btnNotify.setText("Notification enabled");
                                    btnNotify.setTextColor(Color.GRAY);
                                    btnNotify.setEnabled(false);
                                }
                            }
                        });
                    }

                    @Override
                    public void onFail(int code, final String errMsg) {
                        addLog("NotifyOrIndicate onFail:" + errMsg);
                    }

                    @Override
                    public void onExecuteSuccess(OKBLEOperation.OperationType type) {
                        operationType[0] = type;
                    }
                });
                break;
            case ResourceTable.Id_btn_clear:
                tvLog.setText("");
                break;
            case ResourceTable.Id_btn_left:
                onBackPressed();
                break;
            default:
                break;
        }
    }

    /**
     * 添加log文字
     *
     * @param log 内容
     * @since 2021-05-14
     */
    public void addLog(String log) {
        eventHandler.postTask(new Runnable() {
            @Override
            public void run() {
                tvLog.append("\n" + formatTimeYmDhMsF(System.currentTimeMillis()) + " " + log);
            }
        });

    }

    private String formatTimeYmDhMsF(long time) {
        Timestamp ts = new Timestamp(time);
        String timeStr = ts.toString();
        String[] array = timeStr.split(" ");
        if (array.length == 2) {
            return array[1];
        } else {
            return array[0];
        }
    }

    @Override
    public void onConnected(String deviceTag) {

    }

    @Override
    public void onDisconnected(String deviceTag) {

    }

    @Override
    public void onReadBattery(String deviceTag, int battery) {

    }


    @Override
    public void onReceivedValue(String deviceTag, final String uuid, final byte[] value) {
        uuidTemp = uuid;
        InnerEvent event = InnerEvent.get(RECEIVED_VALUE, value);
        handler.sendEvent(event);
    }

    @Override
    public void onWriteValue(String deviceTag, String uuid, byte[] value, boolean success) {

    }

    @Override
    public void onReadValue(String deviceTag, String uuid, byte[] value, boolean success) {

    }

    @Override
    public void onNotifyOrIndicateComplete(String deviceTag, String uuid, boolean enable, boolean success) {

    }
}
